package com.cc.app.ui;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.Point;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import com.cc.app.view.TestView;

public class WaitView extends TestView {

    private Path outerCircle;

    private PathMeasure pathMeasure;

    private Path drawPath;

    private int duration = 500;

    private float ratio;

    private Paint paint;

    private ValueAnimator animator;

    private float rectWidth = 100;
    private float gap = 20;
    private float x0, y0;
    private int status = 0;
    private Point point;
    private Point next;

    private RectF src, dst;

    private boolean finished;

    private RectF outerRect = new RectF(-300, -300, 300, 300);

    public WaitView(Context context) {
        this(context, null);
    }

    public WaitView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        initPaint();
        initListener();
        initAnimator();

        point = new Point(0, 0);
        src = getRect(point);
        next = next();
        dst = getRect(next);
    }

    private void initAnimator() {
        animator = ValueAnimator.ofFloat(0, 1).setDuration(duration);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                ratio = (float) animation.getAnimatedValue();

                x0 = dst.left + (src.left - dst.left) * ratio;
                y0 = dst.top + (src.top - dst.top) * ratio;
                invalidate();
            }
        });

        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation, boolean isReverse) {
                if (status == 2)
                    return;

                if (status == 0) {
                    status = 1;
                    point = new Point(0, 0);
                    next = new Point(0, -1);
                } else if (finished && next.x * next.y == 0) {
                    status = 2;
                    point = new Point(next);
                    next = new Point(0, 0);

                    outerCircle = new Path();
                    outerCircle.addArc(outerRect, getDegree(), 359.9f);
                    drawPath = new Path();

                    pathMeasure = new PathMeasure();
                    pathMeasure.setPath(outerCircle, false);

                } else {
                    point = new Point(next);
                    next = next();
                }

                src = getRect(point);
                dst = getRect(next);

                animator.start();
            }
        });
    }

    private void initListener() {
        this.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                status = 0;
                finished = false;
                animator.start();
            }
        });

        this.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                finished = true;
                return true;
            }
        });
    }

    private void initPaint() {
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(10);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeJoin(Paint.Join.BEVEL);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.save();
        canvas.translate(getWidth() / 2, getHeight() / 2);

        draw4(canvas);
        canvas.restore();
    }


    private void draw4(Canvas canvas) {
        switch (status) {
            case 0:
                paintCircle(canvas, 0, 0);
                break;

            case 1:
                paintCircle(canvas, point.x, point.y, next.x, next.y);
                RectF rect = new RectF(x0, y0, x0 + rectWidth, y0 + rectWidth);
                canvas.save();
                canvas.rotate(-90 * ratio, rect.centerX(), rect.centerY());
                canvas.drawRect(rect, paint);
                canvas.restore();
                break;

            case 2:
                Log.w("point", point.toString());
                Log.w("next", next.toString());

                paintCircle(canvas, point.x, point.y, next.x, next.y);
                rect = new RectF(x0, y0, x0 + rectWidth, y0 + rectWidth);
                canvas.save();
                canvas.rotate(-90 * ratio, rect.centerX(), rect.centerY());
                canvas.drawRect(rect, paint);
                canvas.restore();

                drawPath.reset();
                pathMeasure.setPath(outerCircle, false);
                pathMeasure.getSegment(0, ratio * pathMeasure.getLength(), drawPath, true);

                paint.setStyle(Paint.Style.STROKE);
                canvas.drawPath(drawPath, paint);
                paint.setStyle(Paint.Style.FILL);

                break;
        }
    }

    private RectF getRect(Point p) {
        float x0 = -rectWidth / 2;
        float y0 = -rectWidth / 2;

        int x = p.x;
        int y = p.y;

        if (x != 0) {
            x0 += (x > 0 ? 1 : -1) * (gap + rectWidth);
        }

        if (y != 0) {
            y0 += (y > 0 ? 1 : -1) * (gap + rectWidth);
        }

        float x1 = x0 + rectWidth;
        float y1 = y0 + rectWidth;

        return new RectF(x0, y0, x1, y1);
    }

    private int getDegree() {
        if (point.equals(1, 0))
            return 0;

        return point.x * 180 + point.y * 90;
    }


    private Point next() {
        if (point.equals(0, 0))
            return new Point(0, -1);

        if (point.equals(0, -1))
            return new Point(1, -1);

        if (point.equals(1, -1))
            return new Point(1, 0);

        if (point.equals(1, 0))
            return new Point(1, 1);

        if (point.equals(1, 1))
            return new Point(0, 1);

        if (point.equals(0, 1))
            return new Point(-1, 1);

        if (point.equals(-1, 1))
            return new Point(-1, 0);

        if (point.equals(-1, 0))
            return new Point(-1, -1);

        if (point.equals(-1, -1))
            return new Point(0, -1);

        return new Point(0, 0);
    }

    private void paintCircle(Canvas canvas, int x, int y) {
        paintCircle(canvas, x, y, x, y);
    }

    private void paintCircle(Canvas canvas, int x, int y, int x1, int y1) {
        for (int i = -1; i < 2; i++) {
            for (int k = -1; k < 2; k++) {
                if (i == x && k == y || i == x1 && k == y1)
                    continue;

                paintRect(canvas, i, k);
            }
        }
    }

    private void paintRect(Canvas canvas, int x, int y) {
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.WHITE);
        canvas.save();

        if (x == -1) {
            canvas.translate(-gap - rectWidth, 0);
        } else if (x == 1) {
            canvas.translate(gap + rectWidth, 0);
        }

        if (y == -1) {
            canvas.translate(0, -gap - rectWidth);
        } else if (y == 1) {
            canvas.translate(0, gap + rectWidth);
        }

        canvas.drawRect(-rectWidth / 2, -rectWidth / 2, rectWidth / 2, rectWidth / 2, paint);
        canvas.restore();
    }


    /**
     * 五角星
     *
     * @param canvas
     */
    private void draw2(Canvas canvas) {
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.STROKE);

        int r = 500;
        Path path = new Path();
        path.addArc(new RectF(-r, -r, r, r), -90, -359.9f);

        canvas.drawPath(path, paint);

        PathMeasure m = new PathMeasure();
        m.setPath(path, false);

        Path path2 = new Path();
        path2.moveTo(0, -r);

        float[] pos = new float[2];

        canvas.save();

        Path clip = new Path();
        clip.addCircle(0, 0, 188, Path.Direction.CW);
        path.op(clip, Path.Op.XOR);
        canvas.clipPath(path);

        int p = 0;
        for (int i = 0; i < 5; i++) {
            p = (p + 2) % 5;
            m.getPosTan(m.getLength() * p / 5, pos, null);
            path2.lineTo(pos[0], pos[1]);
        }

        canvas.drawPath(path2, paint);

        canvas.restore();
    }

    /**
     * 太极
     *
     * @param canvas
     */
    private void draw3(Canvas canvas) {
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.FILL);
        int r = 500;
        canvas.drawArc(new RectF(-r, -r, r, r), -90, 180, true, paint);

        paint.setColor(Color.BLACK);
        canvas.drawArc(new RectF(-r, -r, r, r), 90, 180, true, paint);

        canvas.drawCircle(0, -r / 2, r / 2, paint);
        paint.setColor(Color.WHITE);

        canvas.drawCircle(0, r / 2, r / 2, paint);
        canvas.drawCircle(0, -r / 2, r / 8, paint);

        paint.setColor(Color.BLACK);
        canvas.drawCircle(0, r / 2, r / 8, paint);
    }
}
